home *** CD-ROM | disk | FTP | other *** search
/ Programming Languages Suite / ProgramD2.iso / Borland / Borland C++ V5.02 / TUTOROOT.PAK / STEP11.CPP < prev    next >
C/C++ Source or Header  |  1997-05-06  |  13KB  |  546 lines

  1. //----------------------------------------------------------------------------
  2. // ObjectWindows - (C) Copyright 1991, 1994 by Borland International
  3. //   Tutorial application -- step11.cpp
  4. //----------------------------------------------------------------------------
  5. #include <owl/pch.h>
  6. #include <owl/applicat.h>
  7. #include <owl/decmdifr.h>
  8. #include <owl/mdi.h>
  9. #include <owl/mdichild.h>
  10. #include <owl/dc.h>
  11. #include <owl/inputdia.h>
  12. #include <owl/opensave.h>
  13. #include <owl/controlb.h>
  14. #include <owl/buttonga.h>
  15. #include <owl/statusba.h>
  16. #include <owl/gdiobjec.h>
  17. #include <owl/chooseco.h>
  18. #include <classlib/arrays.h>
  19. #include <stdlib.h>
  20. #include <string.h>
  21. #include "step11.rc"
  22.  
  23. typedef TArray<TPoint> TPoints;
  24. typedef TArrayIterator<TPoint> TPointsIterator;
  25.  
  26. class TLine : public TPoints {
  27.   public:
  28.     // Constructor to allow construction from a color and a pen size.
  29.     // Also serves as default constructor.
  30.     TLine(const TColor& color = TColor(0), int penSize = 1) :
  31.       TPoints(10, 0, 10), PenSize(penSize), Color(color) {}
  32.  
  33.     // Functions to modify and query pen attributes.
  34.     int QueryPenSize() const
  35.     {
  36.       return PenSize;
  37.     }
  38.  
  39.     TColor& QueryColor()
  40.     {
  41.       return Color;
  42.     }
  43.  
  44.     void SetPen(const TColor& newColor, int penSize = 0);
  45.     void SetPen(int penSize);
  46.  
  47.     // TLine draws itself.  Returns true if everything went OK.
  48.     virtual bool Draw(TDC&) const;
  49.  
  50.     // The == operator must be defined for the container class, even if unused
  51.     bool operator ==(const TLine& other) const
  52.     {
  53.       return &other == this;
  54.     }
  55.  
  56.     friend ostream& operator <<(ostream& os, const TLine& line);
  57.     friend istream& operator >>(istream& is, TLine& line);
  58.  
  59.   protected:
  60.     int PenSize;
  61.     TColor Color;
  62. };
  63.  
  64. void
  65. TLine::SetPen(int penSize)
  66. {
  67.   if (penSize < 1)
  68.     PenSize = 1;
  69.   else
  70.     PenSize = penSize;
  71. }
  72.  
  73. void
  74. TLine::SetPen(const TColor& newColor, int penSize)
  75. {
  76.   // If penSize isn't the default (0), set PenSize to the new size.
  77.   if (penSize)
  78.     PenSize = penSize;
  79.  
  80.   Color = newColor;
  81. }
  82.  
  83. bool
  84. TLine::Draw(TDC& dc) const
  85. {
  86.   // Set pen for the dc to the values for this line
  87.   TPen pen(Color, PenSize);
  88.   dc.SelectObject(pen);
  89.  
  90.   // Iterates through the points in the line i.
  91.   TPointsIterator j(*this);
  92.   bool first = true;
  93.  
  94.   while (j) {
  95.     TPoint p = j++;
  96.  
  97.     if (!first)
  98.       dc.LineTo(p);
  99.     else {
  100.       dc.MoveTo(p);
  101.       first = false;
  102.     }
  103.   }
  104.   dc.RestorePen();
  105.   return true;
  106. }
  107.  
  108. typedef TArray<TLine> TLines;
  109. typedef TArrayIterator<TLine> TLinesIterator;
  110.  
  111. class TDrawMDIClient : public TMDIClient {
  112.   public:
  113.     TDrawMDIClient() : TMDIClient()
  114.     {
  115.       NewChildNum = 0;
  116.       FileData    = 0;
  117.     }
  118.  
  119.     TMDIChild* InitChild();
  120.  
  121.     TOpenSaveDialog::TData* GetFileData()
  122.     {
  123.       return FileData ? new TOpenSaveDialog::TData(*FileData) : 0;
  124.     }
  125.  
  126.   protected:
  127.     void CmFileNew();
  128.     void CmFileOpen();
  129.     void CmAbout();
  130.  
  131.   private:
  132.     uint16 NewChildNum;
  133.     TOpenSaveDialog::TData *FileData;
  134.  
  135.   DECLARE_RESPONSE_TABLE(TDrawMDIClient);
  136. };
  137.  
  138. DEFINE_RESPONSE_TABLE1(TDrawMDIClient, TMDIClient)
  139.   EV_COMMAND(CM_FILENEW, CmFileNew),
  140.   EV_COMMAND(CM_FILEOPEN, CmFileOpen),
  141.   EV_COMMAND(CM_ABOUT, CmAbout),
  142. END_RESPONSE_TABLE;
  143.  
  144. // TDrawMDIChild must be declared now, because TDrawMDIClient functions
  145. // call TDrawMDIChild's constructor.
  146.  
  147. class TDrawMDIChild : public TMDIChild {
  148.   public:
  149.     TDrawMDIChild(TDrawMDIClient& parent, const char* title = 0);
  150.    ~TDrawMDIChild()
  151.     {
  152.       delete DragDC;
  153.       delete Line;
  154.       delete Lines;
  155.       delete FileData;
  156.     }
  157.  
  158.   protected:
  159.     TDC* DragDC;
  160.     TPen* Pen;
  161.     TLines* Lines;
  162.     TLine* Line; // To hold a single line at a time that later gets
  163.                  // stuck in Lines
  164.     TOpenSaveDialog::TData* FileData;
  165.     bool IsDirty, IsNewFile;
  166.  
  167.     void GetPenSize(); // GetPenSize always calls Line->SetPen().
  168.  
  169.     // Override member function of TWindow
  170.     bool CanClose();
  171.  
  172.     // Message response functions
  173.     void EvLButtonDown(uint, TPoint&);
  174.     void EvRButtonDown(uint, TPoint&);
  175.     void EvMouseMove(uint, TPoint&);
  176.     void EvLButtonUp(uint, TPoint&);
  177.     void Paint(TDC&, bool, TRect&);
  178.     void CmFileSave();
  179.     void CmFileSaveAs();
  180.     void CmPenSize();
  181.     void CmPenColor();
  182.     void SaveFile();
  183.     void OpenFile();
  184.  
  185.   DECLARE_RESPONSE_TABLE(TDrawMDIChild);
  186. };
  187.  
  188. DEFINE_RESPONSE_TABLE1(TDrawMDIChild, TMDIChild)
  189.   EV_WM_LBUTTONDOWN,
  190.   EV_WM_RBUTTONDOWN,
  191.   EV_WM_MOUSEMOVE,
  192.   EV_WM_LBUTTONUP,
  193.   EV_COMMAND(CM_FILESAVE, CmFileSave),
  194.   EV_COMMAND(CM_FILESAVEAS, CmFileSaveAs),
  195.   EV_COMMAND(CM_PENSIZE, CmPenSize),
  196.   EV_COMMAND(CM_PENCOLOR, CmPenColor),
  197. END_RESPONSE_TABLE;
  198.  
  199. // Define TDrawMDIClient functions.
  200.  
  201. TMDIChild*
  202. TDrawMDIClient::InitChild()
  203. {
  204.   char title[15];
  205.   if(!FileData)
  206.     wsprintf(title, "New drawing %d", NewChildNum);
  207.  
  208.   TMDIChild* child = new TDrawMDIChild(*this, FileData ? FileData->FileName : title);
  209.   child->SetIcon(GetApplication(), TResId("IDI_TUTORIAL"));
  210.   return child;
  211. }
  212.  
  213. void
  214. TDrawMDIClient::CmFileNew()
  215. {
  216.   FileData = 0;
  217.   NewChildNum++;
  218.   CreateChild();
  219. }
  220.  
  221. void
  222. TDrawMDIClient::CmFileOpen()
  223. {
  224.   // Create FileData.
  225.   FileData = new TOpenSaveDialog::TData(OFN_HIDEREADONLY|OFN_FILEMUSTEXIST,
  226.                                         "Point Files (*.PTS)|*.pts|", 0, "",
  227.                                         "PTS");
  228.   // As long as the file open operation goes OK...
  229.   if ((TFileOpenDialog(this, *FileData)).Execute() == IDOK)
  230.     // Create the child window.
  231.     CreateChild();
  232.  
  233.   // FileData is no longer needed.
  234.   FileData = 0;
  235. }
  236.  
  237. void
  238. TDrawMDIClient::CmAbout()
  239. {
  240.   TDialog(this, IDD_ABOUT).Execute();
  241. }
  242.  
  243. // Define TDrawMDIChild functions.
  244.  
  245. TDrawMDIChild::TDrawMDIChild(TDrawMDIClient& parent, const char* title) :
  246.   TMDIChild(parent, title)
  247. {
  248.   DragDC  = 0;
  249.   Lines   = new TLines(5, 0, 5);
  250.   Line    = new TLine(TColor::Black, 1);
  251.   IsDirty = false;
  252.  
  253.   // If the parent returns a valid FileData member, this is an open operation
  254.   if(parent.GetFileData()) {
  255.     // Not a new file
  256.     IsNewFile = false;
  257.     // Copy the parent's FileData member, since that'll go away
  258.     FileData = parent.GetFileData();
  259.     OpenFile();
  260.   }
  261.   // But if the parent returns 0, this is a new operation
  262.   else {
  263.     // This is a new file
  264.     IsNewFile = true;
  265.     // Create a new FileData member
  266.     FileData = new TOpenSaveDialog::TData(OFN_HIDEREADONLY|OFN_FILEMUSTEXIST,
  267.                                           "Point Files (*.PTS)|*.pts|", 0, "",
  268.                                           "PTS");
  269.   }
  270. }
  271.  
  272. bool
  273. TDrawMDIChild::CanClose()
  274. {
  275.   if (IsDirty)
  276.     switch(MessageBox("Do you want to save?", "Drawing has changed",
  277.                       MB_YESNOCANCEL | MB_ICONQUESTION)) {
  278.       case IDCANCEL:
  279.         // Choosing Cancel means to abort the close -- return false.
  280.         return false;
  281.  
  282.       case IDYES:
  283.         // Choosing Yes means to save the drawing.
  284.         CmFileSave();
  285.     }
  286.   return true;
  287. }
  288.  
  289. void
  290. TDrawMDIChild::EvLButtonDown(uint, TPoint& point)
  291. {
  292.   if (!DragDC) {
  293.     SetCapture();
  294.     DragDC = new TClientDC(*this);
  295.     Pen    = new TPen(Line->QueryColor(), Line->QueryPenSize());
  296.     DragDC->SelectObject(*Pen);
  297.     DragDC->MoveTo(point);
  298.     Line->Add(point);
  299.     IsDirty = true;
  300.   }
  301. }
  302.  
  303. void
  304. TDrawMDIChild::EvRButtonDown(uint, TPoint&)
  305. {
  306.   GetPenSize();
  307. }
  308.  
  309. void
  310. TDrawMDIChild::EvMouseMove(uint, TPoint& point)
  311. {
  312.   if (DragDC) {
  313.     DragDC->LineTo(point);
  314.     Line->Add(point);
  315.   }
  316. }
  317.  
  318. void
  319. TDrawMDIChild::EvLButtonUp(uint, TPoint&)
  320. {
  321.   if (DragDC) {
  322.     ReleaseCapture();
  323.     Lines->Add(*Line);
  324.     Line->Flush();
  325.     delete DragDC;
  326.     delete Pen;
  327.     DragDC = 0;
  328.   }
  329. }
  330.  
  331. void
  332. TDrawMDIChild::CmPenSize()
  333. {
  334.   GetPenSize();
  335. }
  336.  
  337. void
  338. TDrawMDIChild::CmPenColor()
  339. {
  340.   TChooseColorDialog::TData colors;
  341.   static TColor custColors[16] =
  342.   {
  343.     0x010101L, 0x101010L, 0x202020L, 0x303030L,
  344.     0x404040L, 0x505050L, 0x606060L, 0x707070L,
  345.     0x808080L, 0x909090L, 0xA0A0A0L, 0xB0B0B0L,
  346.     0xC0C0C0L, 0xD0D0D0L, 0xE0E0E0L, 0xF0F0F0L
  347.   };
  348.  
  349.   colors.Flags = CC_RGBINIT;
  350.   colors.Color = TColor(Line->QueryColor());
  351.   colors.CustColors = custColors;
  352.   if (TChooseColorDialog(this, colors).Execute() == IDOK)
  353.     Line->SetPen(colors.Color);
  354. }
  355.  
  356. void
  357. TDrawMDIChild::GetPenSize()
  358. {
  359.   char inputText[6];
  360.   int penSize = Line->QueryPenSize();
  361.  
  362.   wsprintf(inputText, "%d", penSize);
  363.   if ((TInputDialog(this, "Line Thickness",
  364.                         "Input a new thickness:",
  365.                         inputText,
  366.                         sizeof(inputText))).Execute() == IDOK) {
  367.     penSize = atoi(inputText);
  368.  
  369.     if (penSize < 1)
  370.       penSize = 1;
  371.   }
  372.   Line->SetPen(penSize);
  373. }
  374.  
  375. void
  376. TDrawMDIChild::Paint(TDC& dc, bool, TRect&)
  377. {
  378.   // Iterates through the array of line objects.
  379.   TLinesIterator i(*Lines);
  380.  
  381.   while (i)
  382.     i++.Draw(dc);
  383. }
  384.  
  385. void
  386. TDrawMDIChild::CmFileSave()
  387. {
  388.   if (IsNewFile)
  389.     CmFileSaveAs();
  390.   else
  391.     SaveFile();
  392. }
  393.  
  394. void
  395. TDrawMDIChild::CmFileSaveAs()
  396. {
  397.   if (IsNewFile)
  398.     strcpy(FileData->FileName, "");
  399.  
  400.   if ((TFileSaveDialog(this, *FileData)).Execute() == IDOK)
  401.     SaveFile();
  402.  
  403.   SetCaption(FileData->FileName);
  404. }
  405.  
  406. void
  407. TDrawMDIChild::SaveFile()
  408. {
  409.   ofstream os(FileData->FileName);
  410.  
  411.   if (!os)
  412.     MessageBox("Unable to open file", "File Error", MB_OK | MB_ICONEXCLAMATION);
  413.   else {
  414.     // Write the number of lines in the figure
  415.     os << Lines->GetItemsInContainer();
  416.  
  417.     // Append a description using a resource string
  418.     os << ' ' << string(*GetApplication(), IDS_FILEINFO) << '\n';
  419.  
  420.     // Get an iterator for the array of lines
  421.     TLinesIterator i(*Lines);
  422.  
  423.     // While the iterator is valid (i.e. we haven't run out of lines)
  424.     while (i)
  425.       // Copy the current line from the iterator and increment the array.
  426.       os << i++;
  427.  
  428.     // Set new file and dirty display indicator to false.
  429.     IsNewFile = IsDirty = false;
  430.   }
  431. }
  432.  
  433. void
  434. TDrawMDIChild::OpenFile()
  435. {
  436.   ifstream is(FileData->FileName);
  437.  
  438.   if (!is)
  439.     MessageBox("Unable to open file", "File Error", MB_OK | MB_ICONEXCLAMATION);
  440.   else {
  441.     unsigned numLines;
  442.     char fileinfo[100];
  443.  
  444.     Lines->Flush();
  445.     Line->Flush();
  446.  
  447.     is >> numLines;
  448.     is.getline(fileinfo, sizeof(fileinfo));
  449.     Parent->SetCaption(fileinfo);
  450.  
  451.     for (int i = 0; i < numLines; i++) {
  452.       TLine line;
  453.       is >> line;
  454.       Lines->Add(line);
  455.     }
  456.   }
  457.   IsNewFile = IsDirty = false;
  458.   Invalidate();
  459. }
  460.  
  461. class TDrawApp : public TApplication {
  462.   public:
  463.     TDrawApp() : TApplication() {}
  464.  
  465.     void InitMainWindow();
  466. };
  467.  
  468. void
  469. TDrawApp::InitMainWindow()
  470. {
  471.   // Create a decorated MDI frame
  472.   TDecoratedMDIFrame* frame = new TDecoratedMDIFrame("Drawing Pad", TResId("COMMANDS"), *new TDrawMDIClient, true);
  473.  
  474.   // Construct a status bar
  475.   TStatusBar* sb = new TStatusBar(frame, TGadget::Recessed);
  476.  
  477.   // Construct a control bar
  478.   TControlBar* cb = new TControlBar(frame);
  479.   cb->Insert(*new TButtonGadget(CM_FILENEW, CM_FILENEW, TButtonGadget::Command));
  480.   cb->Insert(*new TButtonGadget(CM_FILEOPEN, CM_FILEOPEN, TButtonGadget::Command));
  481.   cb->Insert(*new TButtonGadget(CM_FILESAVE, CM_FILESAVE, TButtonGadget::Command));
  482.   cb->Insert(*new TButtonGadget(CM_FILESAVEAS, CM_FILESAVEAS, TButtonGadget::Command));
  483.   cb->Insert(*new TSeparatorGadget);
  484.   cb->Insert(*new TButtonGadget(CM_PENSIZE, CM_PENSIZE, TButtonGadget::Command));
  485.   cb->Insert(*new TButtonGadget(CM_PENCOLOR, CM_PENCOLOR, TButtonGadget::Command));
  486.   cb->Insert(*new TSeparatorGadget);
  487.   cb->Insert(*new TButtonGadget(CM_ABOUT, CM_ABOUT, TButtonGadget::Command));
  488.  
  489.   // Insert the status bar and control bar into the frame
  490.   frame->Insert(*sb, TDecoratedFrame::Bottom);
  491.   frame->Insert(*cb, TDecoratedFrame::Top);
  492.  
  493.   // Set the main window and its menu
  494.   SetMainWindow(frame);
  495. }
  496.  
  497. int
  498. OwlMain(int /*argc*/, char* /*argv*/ [])
  499. {
  500.   return TDrawApp().Run();
  501. }
  502.  
  503. ostream&
  504. operator <<(ostream& os, const TLine& line)
  505. {
  506.   // Write the number of points in the line
  507.   os << line.GetItemsInContainer();
  508.  
  509.   // Get and write pen attributes.
  510.   os << ' ' << line.Color << ' ' << line.PenSize;
  511.  
  512.   // Get an iterator for the array of points
  513.   TPointsIterator j(line);
  514.  
  515.   // While the iterator is valid (i.e. we haven't run out of points)
  516.   while(j)
  517.     // Write the point from the iterator and increment the array.
  518.     os << j++;
  519.   os << '\n';
  520.  
  521.   // return the stream object
  522.   return os;
  523. }
  524.  
  525. istream&
  526. operator >>(istream& is, TLine& line)
  527. {
  528.   unsigned numPoints;
  529.   is >> numPoints;
  530.  
  531.   COLORREF color;
  532.   int penSize;
  533.   is >> color >> penSize;
  534.   line.SetPen(TColor(color), penSize);
  535.  
  536.   while (numPoints--) {
  537.     TPoint point;
  538.     is >> point;
  539.     line.Add(point);
  540.   }
  541.  
  542.   // return the stream object
  543.   return is;
  544. }
  545.  
  546.